⚠️ FOR SECURITY TESTING ONLY — This repository contains intentional vulnerabilities designed to evaluate AppSec scanners. Many are deliberately obfuscated. Do NOT deploy to production.
Unlike basic vulnerable apps, this one is built to challenge scanners. Every vulnerability uses at least one evasion technique intended to cause false negatives:
| Evasion Technique | How it tricks scanners |
|---|---|
| Taint through extension methods | Scanner clears taint after .Sanitize() call even if it's a no-op |
| Taint through LINQ | Select(), Aggregate(), string.Join() not tracked as concat sinks |
| Taint through StringBuilder | .Append() not recognised as string concat |
| Taint through reflection | PropertyInfo.GetValue() and MethodInfo.Invoke() drop taint |
| Taint through async/await | Taint lost across await boundary or inside Task.Run() lambda |
| Taint through closures | Captured variable in lambda not tracked back to source |
| Taint through Dictionary | Store + retrieve via key lookup loses taint |
| Implicit conversion operators | Type-safe wrapper looks sanitised, isn't |
| Cross-method taint (3+ hops) | Taint crosses Controller → Service → Service → Sink |
| Second-order injection | Safe write, unsafe read - scanner must track DB as taint source |
| Static constructor secrets | Secrets in static {} block not flagged like field initialisers |
| Named constants hiding values | MIN_ITERATIONS = 1 not obvious without value resolution |
| Helper classes hiding sinks | Sink is in ResponseHelper, UrlBuilder, XmlHelper not controller |
| Broken attribute implementation | [AdminOnly] attribute is a no-op - scanner must inspect impl |
| Ternary branch taint merge | Taint only in false branch of encode ? safe : unsafe |
| Environment variable aliasing | Taint written to env var, read back - scanner must track |
| Base64 decode preserves taint | Value still dangerous after decode |
| Method | Evasion Technique | CWE |
|---|---|---|
Search |
Taint through no-op extension method chain | CWE-89 |
Filter |
string.Join() on tainted array |
CWE-89 |
Login |
StringBuilder.Append() |
CWE-89 |
GetUser |
Taint into private method, interpolated inside | CWE-89 |
Report |
Taint via PropertyInfo.GetValue() reflection |
CWE-89 |
Order |
Multi-step taint across 4 variables | CWE-89 |
ByTags |
LINQ Select().Aggregate() |
CWE-89 |
DecodeAndQuery |
Taint through Convert.FromBase64String() |
CWE-89 |
DictAlias |
Taint stored/retrieved via Dictionary key | CWE-89 |
ImplicitConvert |
Implicit conversion operator wrapper | CWE-89 |
PrepareQuery/ExecuteStored |
Stored taint via instance field | CWE-89 |
FmtQuery |
string.Format with swapped argument order |
CWE-89 |
| Method | Evasion Technique | CWE |
|---|---|---|
Greet |
Taint in ViewBag, XSS in .cshtml @Html.Raw() |
CWE-79 |
Echo |
Taint crosses into ResponseHelper.WriteDirectAsync() |
CWE-79 |
ConvertFile |
ProcessStartInfo.Arguments set separately from FileName |
CWE-78 |
GenerateReport |
Taint via Environment.SetEnvironmentVariable → read back |
CWE-78 |
AsyncExec |
Taint across await Task.Run() boundary |
CWE-78 |
DelegateExec |
Taint captured in Func<> closure, executed later |
CWE-78 |
ReadFile |
Path laundered through Uri constructor |
CWE-22 |
JsonXss |
Tainted object serialised to JSON, written raw | CWE-79 |
LdapSearch |
LDAP filter injection via DirectorySearcher.Filter |
CWE-90 |
ConditionalXss |
Taint only in false branch of ternary | CWE-79 |
LoginReturn |
Open redirect via UrlBuilder.BuildReturnUrl() helper |
CWE-601 |
| Method | Evasion Technique | CWE |
|---|---|---|
LoadState |
BinaryFormatter hidden in ObjectSerializer.Deserialize<T>() |
CWE-502 |
LoadConfig |
TypeNameHandling.All in shared settings object |
CWE-502 |
Proxy |
URL built from 3 separate tainted query params | CWE-918 |
CallWebhook |
SSRF inside WebhookCaller.InvokeAsync() |
CWE-918 |
ParseXml |
XXE resolver set inside XmlHelper.CreateDocument() |
CWE-611 |
DataContractDeser |
KnownTypeProvider includes dangerous types |
CWE-502 |
FetchWithRetry |
SSRF inside retry loop body | CWE-918 |
XmlReaderParse |
DtdProcessing.Parse in XmlSettingsFactory |
CWE-611 |
ValidateInput |
User-controlled regex, 10s DoS window | CWE-1333 |
ReflectionInvoke |
MethodInfo.Invoke() with user-controlled method name |
CWE-470 |
| Item | Evasion Technique | CWE |
|---|---|---|
Encrypt |
DES via CipherFactory.Create("legacy") |
CWE-327 |
HashPassword |
MD5 via variable algo = GetHashAlgorithmName() |
CWE-327 |
EncryptEcb |
ECB mode via (CipherMode)1 integer cast |
CWE-327 |
GenerateToken |
System.Random in class named SecureTokenGenerator |
CWE-338 |
HashPbkdf2 |
MIN_ITERATIONS = 1 hidden in named constant |
CWE-916 |
GenerateRsaKeypair |
512-bit RSA via RSA_KEY_SIZE = 512 constant |
CWE-326 |
DeriveKey |
AES key from DateTime.Today.GetHashCode() |
CWE-338 |
HardcodedKeyStore |
All secrets set in static {} constructor |
CWE-798 |
| Item | Evasion Technique | CWE |
|---|---|---|
DeleteUser |
[AllowAnonymous] overrides class [Authorize] |
CWE-306 |
ValidateToken |
JWT alg:none bypass via case-sensitive string compare | CWE-347 |
GetAdminConfig |
[AdminOnly] attribute is a no-op |
CWE-285 |
SensitiveData |
Role check case-sensitive — "Admin" bypasses "admin" | CWE-284 |
GetProfile |
IDOR checks wrong property (Name not ID) | CWE-639 |
Register |
[Bind] includes IsAdmin, Role fields |
CWE-915 |
ResetPassword |
Non-constant time == comparison |
CWE-208 |
PerformAction |
IsAdmin flag gated only on request body |
CWE-285 |
Login |
Session ID not rotated after login | CWE-384 |
Download |
Path traversal despite file list check | CWE-22 |
| Item | Evasion Technique | CWE |
|---|---|---|
RequestLoggingMiddleware |
Logs full body incl. passwords via structured log | CWE-532 |
SecurityHeadersMiddleware |
Headers only set on 200 — absent on errors/redirects | CWE-693 |
RateLimitMiddleware |
IP taken from X-Forwarded-For header — spoofable |
CWE-807 |
ExceptionHandlerMiddleware |
Full stack trace + hostname in 500 response | CWE-209 |
SessionInitMiddleware |
Cookie missing Secure, HttpOnly, SameSite |
CWE-614 |
UseVulnerableMiddleware |
CORS AllowAnyOrigin() + wrong middleware order |
CWE-942 |
| Item | Evasion Technique | CWE |
|---|---|---|
WebhookService |
SSRF via IHttpClientFactory named client |
CWE-918 |
FileService→DiskWriter |
Path traversal across 3 service hops | CWE-22 |
UserPreferenceService |
Second-order SQL injection (safe write, unsafe read) | CWE-89 |
AnnouncementService |
Stored XSS via IMemoryCache |
CWE-79 |
AuditService |
Log injection via \n in structured log field |
CWE-117 |
EmailTemplateService |
SSTI via user-controlled string.Format template |
CWE-134 |
BalanceService |
TOCTOU race on balance check+debit | CWE-362 |
ArchiveService |
Zip Slip via ZipArchive.Entries[].FullName |
CWE-22 |
| File | Vulnerability | CWE |
|---|---|---|
appsettings.json |
All secrets committed to VCS | CWE-798 |
appsettings.json |
EnableDebugEndpoints: true in production |
CWE-94 |
appsettings.json |
CORS AllowedOrigins: ["*"] |
CWE-942 |
VulnApp.csproj |
System.Text.Encodings.Web RCE (CVE-2021-26701) | Critical |
VulnApp.csproj |
ASP.NET Core auth bypass (CVE-2020-1045) | High |
VulnApp.csproj |
Kestrel DoS (CVE-2022-21986) | High |
VulnApp.csproj |
Newtonsoft.Json path traversal | High |
VulnApp.csproj |
BinaryFormatter (SYSLIB0011) | CWE-502 |
vuln-csharp-app/
└── src/
├── Controllers/
│ ├── SqlObfuscated.cs ← 12 SQLi variants
│ ├── InjectionObfuscated.cs ← XSS, CMDi, LDAP, path traversal
│ ├── DeserializationObfuscated.cs ← Deser, SSRF, XXE, ReDoS
│ ├── CryptoObfuscated.cs ← Weak crypto, hardcoded secrets
│ └── AuthObfuscated.cs ← Auth bypass, IDOR, session fixation
├── Middleware/
│ └── VulnerableMiddleware.cs ← Logging, headers, CORS, cookies
├── Services/
│ └── VulnerableServices.cs ← Cross-service taint, race conditions
├── appsettings.json ← All secrets committed
└── VulnApp.csproj ← Vulnerable NuGet versions